import calendar
import datetime
import json
import logging
import random
import re
import time
import urllib
import uuid

import pymongo
from qcloud_cos import CosConfig, CosS3Client
from sqlalchemy import and_, extract, func
from tornado import httpclient
from tornado.httpclient import HTTPRequest

from base.connection import mongodb_util, redis_util
from base.request import ApiBaseHandler, PCBaseHandler
from common.definition import ret_msg
from conf import config
from conf.config import DOMAIN
from helper.api_helper import ApiHelper
from helper.device import is_owner_device
from helper.payment.pay_util import generator_trade_no
from helper.payment.wechat_pay import md5
from helper.user import UserHelper
from lib.sms.SendTemplateSMS import ccp

logger = logging.getLogger("wechat.handlers.ad")


class Advert(ApiBaseHandler):
    @staticmethod
    def sign(parameters):
        parameters["appkey"] = config.AD_APP_KEY
        # 对各个不为空的键值对的参数名ASCII码从小到大排序（字典序）
        data = sorted(parameters.items(), key=lambda asd: asd[0], reverse=False)
        # 对参数值不为空的键值对拼接成URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串stringA
        str_a = ""
        for item in data:
            k = item[0]
            v = item[1]
            if v and k != "sign":
                str_a += k + "=" + str(v) + "&"
        str_temp = str_a[:-1]
        logger.info(str_temp)
        # 进行md5加密
        sign_value = md5(str_temp.encode())
        return sign_value

    def get_payload(self, url, slot_id, payload, count):
        now = datetime.datetime.now()
        expire_time = (now + datetime.timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")
        ad_info = {}
        ad_info["show-time"] = 15
        if count == 3:
            ad_info["track-url"] = f"https://{DOMAIN}/api/ad/track"
        else:
            ad_info["track-url"] = ""
        if slot_id == config.AD_SLOT_ID1:
            ad_info["slot-id"] = "00000001"
        else:
            ad_info["slot-id"] = "00000002"
        ad_info["width"] = 1024
        ad_info["file-size"] = 100
        ad_info["sign"] = "5795923455ba567d51f90e36c4c7f7dc"
        ad_info["expire-time"] = expire_time
        ad_info["type"] = "IMG"
        ad_info["url"] = url
        ad_info["height"] = 450
        payload.append(ad_info)

    def get_new_payload(self, url, slot_id, payload, img_name):
        now = datetime.datetime.now()
        expire_time = (now + datetime.timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")
        list = ["new_L.png", "i.png", "new_big_L.png", "new_big_I.png"]
        ad_info = {}
        content = []
        ad_info["show-time"] = 15
        if img_name not in list:
            ad_info["track-url"] = "https://ad.style999.com/api/ad/track"
        else:
            ad_info["track-url"] = ""
        ad_info["expire-time"] = expire_time
        ad_info["type"] = "IMG"
        if slot_id == config.AD_SLOT_ID1:
            ad_info["slot-id"] = "00000001"
        else:
            ad_info["slot-id"] = "00000002"
        ad_dict = dict(
            type="IMG",
            url=url,
            width=1024 if slot_id == config.AD_SLOT_ID1 else 768,
            height=450 if slot_id == config.AD_SLOT_ID1 else 1341,
            sign="5795923455ba567d51f90e36c4c7f7dc"
        )
        ad_dict["file-size"] = 100
        ad_dict["music-url"] = ""
        content.append(ad_dict)
        ad_info["content"] = content
        payload.append(ad_info)

    def add_mov_payload(self, slot_id, payload):
        url = "https://cos.style999.com/static/ad/video/test.mp4"
        now = datetime.datetime.now()
        expire_time = (now + datetime.timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")
        ad_info = {}
        content = []
        ad_info["show-time"] = 140
        ad_info["track-url"] = ""
        ad_info["expire-time"] = expire_time
        ad_info["type"] = "MOV"
        if slot_id == config.AD_SLOT_ID1:
            ad_info["slot-id"] = "00000001"
        else:
            ad_info["slot-id"] = "00000002"
        ad_dict = dict(
            type="MOV",
            url=url,
            width=640,
            height=368,
            sign="5795923455ba567d51f90e36c4c7f7dc"
        )
        ad_dict["file-size"] = 8970
        content.append(ad_dict)
        ad_info["content"] = content
        payload.append(ad_info)

    def add_combo_payload(self, slot_id, payload):
        mv_url = "https://cos.style999.com/static/ad/video/test.mp4"
        img_url = "https://cos.style999.com/static/ad/img/red_wine.png"
        now = datetime.datetime.now()
        expire_time = (now + datetime.timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")
        ad_info = {}
        content = []
        ad_info["show-time"] = 60
        ad_info["track-url"] = ""
        ad_info["expire-time"] = expire_time
        ad_info["type"] = "COMBO"
        ad_info["slot-id"] = "00000002"
        count = 2
        while count > 0:
            if count == 2:
                ad_dict = dict(
                    type="MOV",
                    url=mv_url,
                    width=768,
                    height=441,
                    sign="5795923455ba567d51f90e36c4c7f7dc"
                )
                ad_dict["file-size"] = 8970
            else:
                ad_dict = dict(
                    type="IMG",
                    url=img_url,
                    width=768,
                    height=900,
                    sign="5795923455ba567d51f90e36c4c7f7dc"
                )
                ad_dict["file-size"] = 148
            content.append(ad_dict)
            count -= 1
        ad_info["content"] = content
        payload.append(ad_info)

    def combo_payload(self, slot_id, payload):
        mv_url = "https://cos.style999.com/static/ad/video/test.mp4"
        img_url = "https://cos.style999.com/static/ad/img/red_wine.png"
        now = datetime.datetime.now()
        expire_time = (now + datetime.timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")
        ad_info = {}
        content = []
        ad_info["show-time"] = 60
        ad_info["track-url"] = ""
        ad_info["expire-time"] = expire_time
        ad_info["type"] = "COMBO"
        ad_info["slot-id"] = "00000002"
        count = 2
        while count > 0:
            if count == 2:
                ad_dict = dict(
                    type="IMG",
                    url=img_url,
                    width=768,
                    height=900,
                    sign="5795923455ba567d51f90e36c4c7f7dc"
                )
                ad_dict["music-url"] = ""
                ad_dict["file-size"] = 148
            else:
                ad_dict = dict(
                    type="MOV",
                    url=mv_url,
                    width=768,
                    height=441,
                    sign="5795923455ba567d51f90e36c4c7f7dc"
                )
                ad_dict["file-size"] = 8970
            content.append(ad_dict)
            count -= 1
        ad_info["content"] = content
        payload.append(ad_info)

    def default_ad(self, slot_id):
        # url = config.DS_APP_URL % (config.DS_ACCESS_TOKEN, device_id, timestamp)
        payload = []
        base_url = "https://cos.style999.com/static/ad/img/{name}"
        small_list = ["new_L.png", "i.png", "s_dbang.jpg"]
        big_list = [
            "new_big_L.png", "new_big_I.png", "dbang.jpg",
            "new_introduction.png", "car_ad.jpg", "oven.jpg",
            "dried_fruit.jpg", "cup_machine.jpg", "eye.png",
            "fenwine.png", "Insurance.png", "mate20.png",
            "mix3.png", "skll.png", "jd.png", "floor.png"
        ]

        if slot_id == config.AD_SLOT_ID1:
            list = small_list
        elif slot_id == config.AD_SLOT_ID2:
            list = big_list
        else:
            list = []

        for img_name in list:
            url = base_url.format(name=img_name)
            self.get_new_payload(url, slot_id, payload, img_name)

        if slot_id != config.AD_SLOT_ID1:
            self.add_combo_payload(slot_id, payload)
            self.combo_payload(slot_id, payload)

        result = dict(
            code=0,
            message="OK",
            payload=payload
        )
        return result

    async def get(self):
        # 每天10:00 - 22:00播放广告，其他时间段不播放
        day_now = time.localtime()
        date_now = datetime.datetime.now()
        year = day_now.tm_year
        month = day_now.tm_mon
        day = day_now.tm_mday
        # 设置广告播放时段
        ad_begin = datetime.datetime(year, month, day, 10, 0, 0)
        ad_end = datetime.datetime(year, month, day, 22, 0, 0)
        if date_now < ad_begin or date_now > ad_end:
            context = dict(
                code=2,
                payload=[],
                message="非广告播放时间"
            )
            return self.write(context)

        class Device(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_device_owner", "model": Device},
        ])
        device_id = self.get_argument("device_id", "")  # "100025540"
        device = session.query(Device).filter_by(ebf_device_id=device_id).first()
        if not (device_id and device):
            context = dict(
                code=-1,
                payload=[],
                message="请求参数device_id错误"
            )
            session.close()
            return self.write(context)
        ip = self.request.remote_ip
        if device.ebf_device_wifi_code == "CWD-30E1":
            slot_id = config.AD_SLOT_ID1  # 小屏
        elif device.ebf_device_wifi_code == "CWD-30E3":
            slot_id = config.AD_SLOT_ID2  # 大屏
        else:
            slot_id = config.AD_SLOT_ID2

        # 请求第三方广告服务器
        quantity = 8
        appid = config.AD_APP_ID
        sequence = generator_trade_no()
        timestamp = int(str(time.time() * 1000).split(".")[0])
        version = config.AD_APP_VERSION
        payload = {"device-uuid": device_id, "slot-id": slot_id, "quantity": quantity, "type": "IMG", "ip": ip}
        parameters = dict(
            payload=json.dumps(payload),
            appid=appid,
            version=version,
            sequence=sequence,
            timestamp=timestamp
        )
        sign_value = Advert.sign(parameters)
        parameters["sign"] = sign_value

        url = config.AD_APP_URL
        # 使用tornado的异步请求
        http = httpclient.AsyncHTTPClient()
        request = HTTPRequest(
            url=url,
            method="POST",
            validate_cert=False,
            request_timeout=30,
            body=urllib.parse.urlencode(parameters)
        )
        try:
            response = None
            response = await http.fetch(request)
        except Exception as e:
            logger.error(e)
            result = dict(
                code=-1,
                message="广告服务器接口返回信息错误",
                error=str(e)
            )
            session.close()
            return self.write(result)
        if not response:
            context = dict(
                code=-1,
                message="广告服务器响应超时"
            )
            session.close()
            return self.write(context)
        result = json.loads(response.body.decode())
        logger.info(result)
        resp = json.dumps(result)

        create_date = datetime.datetime.now()
        data = dict(
            _id=sequence,
            resp=resp,
            device_id=device_id,
            ip=ip,
            create_date=create_date
        )
        if int(result.get("code", 1)) == 0:
            try:
                db = mongodb_util.db
                db.ad_device_info.insert(data)
                logger.info("ad_device_info:success device_id=%s, ip=%s" % (device_id, ip))
            except Exception as e:
                logger.error("ad_device_info:fail device_id=%s, ip=%s, err=%s" % (device_id, ip, e))
        # else:
        #     if str(result.get("code", 1)) == "-10002":
        #         result = self.default_ad(slot_id)
        #     else:
        #         logger.error(result)

        # result = self.default_ad(slot_id)
        session.close()
        return self.write(result)


class AdvertTrack(ApiBaseHandler):
    async def get(self):
        device_id = self.get_argument("device_id", "")
        track_url = self.get_argument("track_url", "")
        slot_id = self.get_argument("slot_id", "")
        if not device_id:
            return self.write(ret_msg(code=-1, error_message="请求参数device_id错误"))
        logger.info("slot_id=%s, device_id=%s" % (slot_id, device_id))
        if not track_url:
            logger.info("上报地址为空: slot_id=%s, device_id=%s" % (slot_id, device_id))
            return self.write(ret_msg())
        timestamp = int(str(time.time() * 1000).split(".")[0])
        create_date = datetime.datetime.now()
        data = dict(
            device_id=device_id,
            timestamp=timestamp,
            track_url=track_url,
            slot_id=slot_id,
            create_date=create_date
        )
        try:
            db = mongodb_util.db
            db.ad_device_track.insert(data)
            logger.info("ad_device_track:success device_id=%s, create_date=%s" % (device_id, create_date))
        except Exception as e:
            logger.error("ad_device_track:fail device_id=%s, create_date=%s, err=%s" % (device_id, create_date, e))
            return self.write(ret_msg(code=-1, error_message="上报处理失败"))
        return self.write(ret_msg())


class AdStatistics(ApiBaseHandler):
    async def get(self):
        device_id = self.get_argument("device_id", None)
        track_url = self.get_argument("track_url", None)
        slot_id = self.get_argument("slot_id", None)
        time_range = self.get_argument("time_range", None)

        db = mongodb_util.db

        if time_range:
            start_time, end_time = ApiHelper.get_time_range(time_range)
        else:
            start_time = datetime.datetime(2018, 7, 1, 0, 0, 0)
            end_time = datetime.datetime.now()

        if not (device_id or track_url or slot_id):
            result = db.ad_device_track.find(
                {"create_date": {"$gte": start_time, "$lte": end_time}}
            )

        if device_id and track_url and slot_id:
            result = db.ad_device_track.find(
                {
                    "create_date": {"$gte": start_time, "$lte": end_time},
                    "device_id": device_id,
                    "track_url": track_url,
                    "slot_id": slot_id
                }
            )
        elif device_id and track_url:
            result = db.ad_device_track.find(
                {
                    "create_date": {"$gte": start_time, "$lte": end_time},
                    "device_id": device_id,
                    "track_url": track_url,
                }
            )
        elif device_id and slot_id:
            result = db.ad_device_track.find(
                {
                    "create_date": {"$gte": start_time, "$lte": end_time},
                    "device_id": device_id,
                    "slot_id": slot_id,
                }
            )
        elif track_url and slot_id:
            result = db.ad_device_track.find(
                {
                    "create_date": {"$gte": start_time, "$lte": end_time},
                    "track_url": track_url,
                    "slot_id": slot_id,
                }
            )
        elif device_id:
            result = db.ad_device_track.find(
                {
                    "create_date": {"$gte": start_time, "$lte": end_time},
                    "device_id": device_id,
                }
            )
        elif track_url:
            result = db.ad_device_track.find(
                {
                    "create_date": {"$gte": start_time, "$lte": end_time},
                    "track_url": track_url,
                }
            )
        elif slot_id:
            result = db.ad_device_track.find(
                {
                    "create_date": {"$gte": start_time, "$lte": end_time},
                    "slot_id": slot_id,
                }
            )

        count = result.count()
        context = dict(
            count=count
        )
        return self.write(ret_msg(data=context))


class Register(ApiBaseHandler):
    async def get(self):
        mobile = self.get_argument("mobile", None)
        if not mobile:
            return self.write(ret_msg(code=-1, error_message="手机号为空"))

        if not re.match(r"^1\d{10}$", mobile):
            return self.write(ret_msg(code=-1, error_message="手机号格式不正确"))

        sms_code = redis_util.client.get("sms_code_%s" % mobile)
        if sms_code:
            return self.write(ret_msg(code=-1, error_message="验证码已发送，如未收到请稍后重试"))

        sms_code = "%06d" % random.randint(0, 999999)
        try:
            redis = redis_util.client
            redis.setex("sms_code_%s" % mobile, config.SMS_CODE_EXPIRES_SECONDS, sms_code)
        except Exception as e:
            logging.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试！"))

        try:
            result = ccp.sendTemplateSMS(mobile, [sms_code, int(config.SMS_CODE_EXPIRES_SECONDS / 60)], config.TEMP_ID)
            statusCode = result.get("statusCode")
            if statusCode != "000000":
                if statusCode == "160038":
                    return self.write(ret_msg(code=-1, error_message="获取短信验证码过于频繁"))
                elif statusCode == "160040":
                    return self.write(ret_msg(code=-1, error_message="获取短信验证码条数超出当天上限"))
                return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试！"))
        except Exception as e:
            logging.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试！"))
        return self.write(ret_msg(data="OK"))

    async def post(self):
        mobile = self.get_parameter("mobile", None)
        if not mobile:
            return self.write(ret_msg(code=-1, error_message="手机号为空"))
        if not re.match(r"^1\d{10}$", mobile):
            return self.write(ret_msg(code=-1, error_message="手机号格式不正确"))
        user_code = self.get_parameter("sms_code", None)
        if not user_code:
            return self.write(ret_msg(code=-1, error_message="验证码不能为空！"))
        try:
            redis = redis_util.client
            sms_code = redis.get("sms_code_%s" % mobile)
        except Exception as e:
            logging.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙，请重试"))
        if not sms_code:
            return self.write(ret_msg(code=-1, error_message="验证码已过期"))

        if user_code != sms_code.decode("utf-8"):
            return self.write(ret_msg(code=-1, error_message="验证码错误"))

        class User(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])
        open_id = await self.get_open_id()
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            logger.info("创建用户 open_id=%s" % open_id)
            user_dict = dict(
                openid=open_id
            )
            UserHelper.create_user(user_dict, config.DEFAULT_AGENCY_UID)
            user = session.query(User).filter_by(ebf_user_id=open_id).first()
        user.ebf_user_phone = mobile
        session.commit()
        session.close()
        return self.write(ret_msg())


class SourceUpload(ApiBaseHandler):
    async def post(self):
        class User(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])
        open_id = await self.get_open_id()
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            return self.write(ret_msg(code=-1, error_message="请先注册再上传素材！"))
        mobile = user.ebf_user_phone
        if not mobile:
            return self.write(ret_msg(code=-1, error_message="请先注册再上传素材！"))
        source = self.request.files.get("source", None)
        if not source:
            return self.write(ret_msg(code=-1, error_message="请上传素材, 可以是图片或者视频！"))
        urls = []
        if source:
            secret_id = config.COS_APP_SECRET_ID
            secret_key = config.COS_APP_SECRET_KEY
            region = "ap-guangzhou"
            token = ''
            scheme = "https"
            cfg = CosConfig(Region=region, Secret_id=secret_id, Secret_key=secret_key, Token=token, Scheme=scheme)
            client = CosS3Client(cfg)
            base_url = "https://" + "style-1251902022." + "file.myqcloud.com/static/ad/"
            type = [".jpg", ".png", ".gif", ".bmp", ".svg", ".mov", ".mp3", ".mp4", ".avi", ".mid"]
            for s in source:
                filename = s["filename"]
                file_end = filename[-4:]
                filename = generator_trade_no() + "_" + s['filename']
                if file_end not in type:
                    return self.write(ret_msg(code=-1, error_message="素材的格式不支持！"))

                if file_end in [".mov", ".mp4", ".avi", ".mid"]:
                    base_url += "video/"
                    key = "static/ad/video/" + filename
                else:
                    base_url += "img/"
                    key = "static/ad/img/" + filename
                response = client.put_object(
                    Bucket=config.COS_BUCKET + "-" + config.COS_APP_ID,
                    Body=s['body'],
                    Key=key
                )
                url = base_url + filename
                urls.append(url)
            logger.debug(response)
        logger.debug(urls)
        show_time = int(self.get_parameter("show_time", 15))
        if show_time < 5 or show_time > 30:
            return self.write(ret_msg(code=-1, error_message="播放时长在5~30秒之间！"))
        time_range = self.get_parameter("time_range", "08:00-23:59")  # time_range = 08:00-10:00
        interval_time = int(self.get_parameter("interval_time", 15))
        count = int(self.get_parameter("count", 0))
        if count < 1:
            return self.write(ret_msg(code=-1, error_message="请设置正确的播放次数！"))
        area = self.get_parameter("area", "广东省 深圳市")
        data = dict(
            ad_id=generator_trade_no(),  # 广告唯一标识
            open_id=open_id,  # 广告发布人open_id
            urls=json.dumps(urls),  # 上传的图片或视频保存在腾讯云上地址集合
            show_time=show_time,  # 每一次播放时间
            time_range=time_range,  # 广告播放时间段
            interval_time=interval_time,  # 间隔时间
            count=count,  # 播放次数
            area=area,  # 播放地区
            status=0,  # 0=待审核， 1=播放中， 2=已播放
            create_date=datetime.datetime.now(),  # 发布时间
            update_date=datetime.datetime.now(),  # 修改时间
            played_count=0,  # 已播放次数
            pay_status=0,  # 0=未支付， 1=已支付
            is_delete=0  # 是否删除， 0=未删除， 1=已删除
        )
        try:
            db = mongodb_util.db
            db.sdec_ad_source_upload.insert(data)
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="广告资源上传失败，请稍后重试！"))
        return self.write(ret_msg())


class PersonCenter(ApiBaseHandler):
    async def get(self):
        class User(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])
        open_id = await self.get_open_id()
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            return self.write(ret_msg(code=-1, error_message="请先注册！"))
        mobile = user.ebf_user_phone
        if not mobile:
            return self.write(ret_msg(code=-1, error_message="请先注册！"))
        nickname = user.ebf_user_nickname
        headurl = user.ebf_user_headurl
        base_num = 7  # "最近"的判断标准，一周内上传为"最近"
        page_index = int(self.get_argument("page_index", 0))
        page_size = int(self.get_argument("page_size", 10))
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size
        now = datetime.datetime.now()
        base_date = (now + datetime.timedelta(days=-base_num)).replace(hour=0, minute=0, second=0, microsecond=0)
        source = []
        try:
            db = mongodb_util.db
            total = db.sdec_ad_source_upload.find({"is_delete": 0, "open_id": open_id}).count()
            wait_audit_count = db.sdec_ad_source_upload.find({"is_delete": 0, "status": 0, "open_id": open_id}).count()
            playing_count = db.sdec_ad_source_upload.find({"is_delete": 0, "status": 1, "open_id": open_id}).count()
            played_count = db.sdec_ad_source_upload.find({"is_delete": 0, "status": 2, "open_id": open_id}).count()
            result = db.sdec_ad_source_upload.find({
                "is_delete": 0,
                "open_id": open_id,
                "create_date": {"$gte": base_date}
            })
            result = result.sort("ad_id", pymongo.DESCENDING).skip(page_start).limit(page_size)
            for r in result:
                status = int(r["status"])
                if status == 0:
                    status = "待审核"
                elif status == 1:
                    status = "播放中"
                elif status == 2:
                    status = "已播放"
                else:
                    status = "未知"
                source_dict = dict(
                    create_date=r["create_date"].strftime("%Y-%m-%d"),
                    status=status,
                    urls=json.loads(r["urls"]),
                    id=r["ad_id"]
                )
                source.append(source_dict)
            context = dict(
                source=source,
                total=total,
                wait_audit_count=wait_audit_count,
                playing_count=playing_count,
                played_count=played_count,
                nickname=nickname,
                headurl=headurl,
                open_id=open_id
            )
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试！"))
        return self.write(ret_msg(data=context))


class AdList(ApiBaseHandler):
    async def get(self):
        class User(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])
        open_id = await self.get_open_id()
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            return self.write(ret_msg(code=-1, error_message="请先注册！"))
        mobile = user.ebf_user_phone
        if not mobile:
            return self.write(ret_msg(code=-1, error_message="请先注册！"))
        status = int(self.get_argument("status", 0))
        page_index = int(self.get_argument("page_index", 0))
        page_size = int(self.get_argument("page_size", 10))
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size
        try:
            db = mongodb_util.db
            result = db.sdec_ad_source_upload.find({
                "is_delete": 0,
                "open_id": open_id,
                "status": status
            })
            result = result.sort("create_date", pymongo.DESCENDING).skip(page_start).limit(page_size)
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试！"))
        source = []
        for r in result:
            if status == 0:
                type = "待审核"
            elif status == 1:
                type = "播放中"
            elif status == 2:
                type = "已播放"
            else:
                type = "未知"
            source_dict = dict(
                create_date=r["create_date"].strftime("%Y-%m-%d"),
                type=type,
                urls=json.loads(r["urls"]),
                id=r["ad_id"]
            )
            source.append(source_dict)
        return self.write(ret_msg(data=source))


class AdBill(ApiBaseHandler):
    async def get(self):
        class User(object):
            pass

        class GoodsOrder(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
            {"db_table": "sdet_order", "model": GoodsOrder},
        ])
        open_id = await self.get_open_id()
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            return self.write(ret_msg(code=-1, error_message="请先注册！"))
        mobile = user.ebf_user_phone
        if not mobile:
            return self.write(ret_msg(code=-1, error_message="请先注册！"))
        filters = dict(
            sdef_order_is_delete=0,
            sdef_order_device_id=open_id,
            sdef_order_pay_status=1,
            sdef_order_status=4,
            sdef_order_type=5
        )
        result = session.query(
            func.date_format(GoodsOrder.sdef_order_create_time, '%Y-%m').label('date'),
            func.sum(GoodsOrder.sdef_order_fee).label('total_fee')
        ).filter_by(**filters).group_by('date').order_by(GoodsOrder.sdef_order_create_time.desc()).all()
        data = []
        for r in result:
            year = int(r.date[:4])
            month = int(r.date[5:7])
            total_fee = r.total_fee
            orders = session.query(GoodsOrder).filter_by(
                **filters
            ).filter(and_(
                extract('year', GoodsOrder.sdef_order_create_time) == year,
                extract('month', GoodsOrder.sdef_order_create_time) == month)
            ).order_by(GoodsOrder.sdef_order_create_time.desc()).all()
            order_list = []
            for o in orders:
                order_dict = dict(
                    time=o.sdef_order_create_time.strftime("%m-%d"),
                    fee=str(o.sdef_order_fee)
                )
                order_list.append(order_dict)
            result_dict = dict(
                total_fee=str(total_fee),
                date=r.date,
                orders=order_list
            )
            data.append(result_dict)
        return self.write(ret_msg(data=data))


class AddAd(PCBaseHandler):
    mov_type = ["mp4", "mov", "avi", "mid", "3gp"]
    img_type = ["jpg", "png", "gif", "bmp", "jpeg", "heif", "heic"]
    music_type = ["mp3"]

    def get_single_content(self, type, music_url, url, sign, width, height):
        """
        生成图片或视频单一的广告内容
        :param type:
        :param music_url:
        :param url:
        :param sign:
        :param width:
        :param height:
        :return:
        """
        file_size = 650
        resource_info = dict(
            type=type,
            url=url,
            width=width,
            height=height,
            sign=sign
        )
        resource_info["file-size"] = file_size
        resource_info["music-url"] = music_url
        return resource_info

    def get_combo_content(self, music_url, url, sign):
        """
        生成视频图片组合的广告内容
        :param music_url:
        :param url:
        :param sign:
        :return:
        """
        content = []
        url_list = url
        url_one = url_list[0]
        url_two = url_list[1]
        img_type = self.img_type
        url_one_end = url_one.split(".")[-1]

        if url_one_end.lower() in img_type:
            img_url = url_one
            mov_url = url_two
        else:
            img_url = url_two
            mov_url = url_one

        i_type = "IMG"
        m_type = "MOV"
        img_info = self.get_single_content(i_type, music_url, img_url, sign, width=768, height=900)
        mov_info = self.get_single_content(m_type, music_url, mov_url, sign, width=768, height=441)

        if url_one_end.lower() in img_type:
            content.append(img_info)
            content.append(mov_info)
        else:
            content.append(mov_info)
            content.append(img_info)

        return content

    def get_resource_info(self, type, url, sign, slot_id, music_url=None):
        """
        返回广告的总体结构
        :param type:
        :param url:
        :param sign:
        :param music_url:
        :return:
        """
        ad_info = {}
        content = []
        show_time = int(self.get_parameter("show_time", 15))
        track_url = self.get_parameter("track_url", None)
        source = int(self.get_parameter("source", 2))
        if source in [1, 2]:
            track_url = None
        elif track_url:
            pass
        else:
            track_url = "https://ad.style999.com/api/ad/track"

        if slot_id == "00000001":
            width = 1024
            height = 440
        if slot_id == "00000002":
            width = 768
            height = 1341

        if type != "COMBO":
            resource_info = self.get_single_content(type, music_url, url, sign, width, height)
            content.append(resource_info)
        else:
            content = self.get_combo_content(music_url, url, sign)

        ad_info["show-time"] = show_time
        ad_info["track-url"] = track_url
        ad_info["expire-time"] = None
        ad_info["type"] = type
        ad_info["slot-id"] = slot_id
        ad_info["content"] = content
        return ad_info

    def upload_img(self, upload_type, sign, urls, slot_id):
        """
        上传图片广告 宽768 高1341
        :param upload_type:
        :param sign:
        :param urls:
        :return:
        """
        type = "IMG"
        music_url = self.get_parameter("music_url", None)
        if upload_type == 1:
            if len(urls) == 1:  # 只有图片
                url = urls[0]
            elif len(urls) == 2:  # 图片和背景音乐
                url_one = urls[0]
                url_two = urls[1]
                one_end = url_one.split(".")[-1]
                if one_end.lower() in self.img_type:
                    url = url_one
                    music_url = url_two
                else:
                    url = url_two
                    music_url = url_one
        elif upload_type == 2:
            url = self.get_parameter("resource_url", None)

        ad_info = self.get_resource_info(type, url, sign, slot_id, music_url)
        url_list = []
        url_list.append(url)
        return ad_info, url_list

    def upload_mov(self, upload_type, sign, urls, slot_id):
        """
        上传视频广告 宽768 高1341
        :param upload_type:
        :param sign:
        :param urls:
        :return:
        """
        type = "MOV"
        music_url = None
        if upload_type == 1:
            url = urls[0]
        elif upload_type == 2:
            url = self.get_parameter("resource_url", None)

        ad_info = self.get_resource_info(type, url, sign, slot_id, music_url)
        url_list = []
        url_list.append(url)
        return ad_info, url_list

    def upload_combo(self, upload_type, sign, urls, slot_id):
        """
        上传图片视频组合广告 图片：宽768 高441 视频：宽768 高900
        :param upload_type:
        :param sign:
        :param urls:
        :return:
        """
        type = "COMBO"
        music_url = None
        if upload_type == 1:
            url = urls
        elif upload_type == 2:
            url_str = self.get_parameter("resource_url", None)
            url = url_str.split(",")
        ad_info = self.get_resource_info(type, url, sign, slot_id, music_url)
        return ad_info, url

    def get_screen_type(self, device_id):
        class Device(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_device_owner", "model": Device},
        ])
        device = session.query(Device).filter_by(ebf_device_id=device_id).first()
        if not device:
            session.close()
            return False
        if device.ebf_device_wifi_code == "CWD-30E1":
            slot_id = "00000001"  # 小屏
        else:
            slot_id = "00000002"  # 大屏
        session.close()
        return slot_id

    async def post(self):
        company_name = self.get_parameter("company_name", "思达尔实业")  # 公司名称
        ad_describe = self.get_parameter("ad_describe", "内部广告")  # 广告描述
        resource = self.request.files.get("resource", None)  # 素材
        resource_url = self.get_parameter("resource_url", None)  # 素材地址
        type = self.get_parameter("type", "互联网")  # 广告类型： 即广告内容所属行业
        time_range = self.get_parameter("time_range", "8:00-23:59")  # 广告播放时间段
        days = self.get_parameter("days", "10")  # 播放天数
        play_area = self.get_parameter("play_area", "深圳")  # 广告播放地区
        show_time = self.get_parameter("show_time", 15)  # 每次展示时间, 以秒为单位
        track_url = self.get_parameter("track_url", None)  # 上报地址
        fee = self.get_parameter("fee", 100)  # 广告金额
        message = self.get_parameter("message", None)  # 留言
        music_url = self.get_parameter("music_url", None)  # 图片背景音乐

        # 表单控件以外需要传递的参数
        upload_type = self.get_parameter("upload_type", None)  # 上传方式: 1=上传文件, 2=上传文件地址
        play_type = self.get_parameter("play_type", None)  # 广告播放方式： 1=img, 2=mov, 3=combo
        slot_id = self.get_parameter("slot_id", None)  # 1=00000001小屏, 2=00000002大屏
        scene = int(self.get_parameter("scene", 0))  # 播放场景 0=未知 1=家庭 2=办公室 3=餐厅 4=车行 5=社区店
        source = int(self.get_parameter("source", 2))  # 广告来源 0=未知 1=家庭数码相框 2=公司内部广告 3=第三方广告 4=私人付费广告
        devices = self.get_parameter("devices", None)  # 播放设备
        db = mongodb_util.db
        if scene == 1:
            open_id = await self.get_open_id()
            slot_id = self.get_screen_type(devices)
            if not slot_id:
                return self.write(ret_msg(code=-1, error_message="设备编号错误"))
            count = db.sdec_ad_resource.find({
                "slot_id": slot_id,
                "devices": devices,
                "is_delete": 0,
                "source": 1
            }).count()
            if not devices:
                return self.write(ret_msg(code=-1, error_message="缺少参数设备编号！"))
            if count > 100:
                return self.write(ret_msg(code=-1, error_message="累计上传照片数目不能超过100！"))
            result = is_owner_device(devices, open_id)
            if not result:
                return self.write(ret_msg(code=-1, error_message="只有设备主人才能上传图片！"))
            devices = devices.split(",")
        else:
            open_id = None
            devices = devices.split(",") if devices else []
            key = self.get_parameter("key", None)
            if key != "o7qyl0vKx54jB05FjmxNw76SJAPE":
                return self.write(ret_msg(code=-1, error_message="没有操作权限！"))

        if not upload_type:
            return self.write(ret_msg(code=-1, error_message="请选择上传方式！"))

        if not play_type:
            return self.write(ret_msg(code=-1, error_message="请选择播放方式！"))

        if not slot_id and source != 1:
            return self.write(ret_msg(code=-1, error_message="请选择大屏或小屏播放！"))

        if not ([company_name, type, time_range, show_time, days, play_area, fee]):
            return self.write(ret_msg(code=-1, error_message="缺少请求参数！"))

        if not days.isdigit():
            return self.write(ret_msg(code=-1, error_message="广告次数只能是数字！"))

        show_time = int(show_time)
        if show_time < 0 or show_time > 300:
            return self.write(ret_msg(code=-1, error_message="广告每次展示时间不能超过5分钟！"))

        pay_fee = int(days) * show_time * 10 / 15
        if pay_fee != int(fee):
            return self.write(ret_msg(code=-1, error_message="播放天数与金额不匹配！"))

        upload_type = int(upload_type)
        play_type = int(play_type)
        if upload_type == 1:
            if not resource:
                return self.write(ret_msg(code=-1, error_message="请上传素材文件！"))
            if resource_url:
                return self.write(ret_msg(code=-1, error_message="选择的上传方式是上传文件而不是上传地址！"))
        elif upload_type == 2:
            if not resource_url:
                return self.write(ret_msg(code=-1, error_message="请上传素材地址！"))
            if resource:
                return self.write(ret_msg(code=-1, error_message="选择的上传方式是上传地址而不是上传文件！"))
        else:
            return self.write(ret_msg(code=-1, error_message="不合法的上传方式！"))

        if play_type not in [1, 2, 3]:
            return self.write(ret_msg(code=-1, error_message="不合法的播放方式！"))

        if int(slot_id) not in [1, 2] and source != 1:
            return self.write(ret_msg(code=-1, error_message="不支持的屏幕类型！"))

        if upload_type == 2 and play_type == 3:
            url_list = resource_url.split(",")
            if len(url_list) != 2:
                return self.write(ret_msg(code=-1, error_message="组合广告只能含有一个图片地址和一个视频地址且逗号隔开！"))

        size = int(self.request.headers.get("Content-Length")) / 1024
        logger.info("size=%s" % size)
        if size > 80000:
            return self.write(ret_msg(code=-1, error_message="上传文件不能大于80M！"))

        urls = []
        # 上传文件到腾讯文存储
        if resource:
            secret_id = config.COS_APP_SECRET_ID
            secret_key = config.COS_APP_SECRET_KEY
            region = "ap-guangzhou"
            token = ''
            scheme = "https"
            cfg = CosConfig(Region=region, Secret_id=secret_id, Secret_key=secret_key, Token=token, Scheme=scheme)
            client = CosS3Client(cfg)
            # 图片格式：jpg, png, gif; 视频格式：mp4, mov, avi, mid, 3gp; 音乐格式：mp3
            resource_type = ["jpg", "png", "gif", "bmp", "jpeg", "heif",
                             "heic", "mp4", "mov", "avi", "mid", "3gp", "mp3"]
            if scene == 1:
                base_url = f"https://cos.style999.com/static/user/{open_id}/{devices[0]}/"
                base_key_pre = f"static/user/{open_id}/{devices[0]}/"
            else:
                base_url = "https://cos.style999.com/static/ad/"
                base_key_pre = "static/ad/"
            video_url = base_url + "video/"
            img_url = base_url + "img/"
            mic_url = base_url + "music/"
            video_key_pre = base_key_pre + "video/"
            img_key_pre = base_key_pre + "img/"
            mic_key_pre = base_key_pre + "music/"
            response = None
            for s in resource:
                filename = s["filename"]
                file_end = filename.split(".")[-1]
                filename = generator_trade_no() + "_" + s['filename']
                if file_end.lower() not in resource_type:
                    logger.info(f"open_id={open_id}, format(img)={file_end}, filename={filename}")
                    return self.write(ret_msg(code=-1, error_message="素材的格式不支持！"))

                if file_end.lower() in self.mov_type:
                    url = video_url + filename
                    key = video_key_pre + filename
                elif file_end.lower() in self.img_type:
                    url = img_url + filename
                    key = img_key_pre + filename
                elif file_end.lower() in self.music_type:
                    url = mic_url + filename
                    key = mic_key_pre + filename
                else:
                    continue
                response = client.put_object(
                    Bucket=config.COS_BUCKET + "-" + config.COS_APP_ID,
                    Body=s['body'],
                    Key=key
                )
                urls.append(url)
            logger.debug(response)

        if urls:
            if play_type == 1 and len(urls) > 2:
                return self.write(ret_msg(code=-1, error_message="一次只能上传一张图片或者一张图片和一个音乐文件！"))
            if play_type == 2 and len(urls) != 1:
                return self.write(ret_msg(code=-1, error_message="一次只能上传一个视频文件！"))
            if play_type == 3 and len(urls) != 2:
                return self.write(ret_msg(code=-1, error_message="一次只能上传一张图片和一个视频文件！"))

        if source != 1:
            if slot_id == "1":
                slot_id = "00000001"
            else:
                slot_id = "00000002"

        sign = uuid.uuid4().hex  # 唯一字符串
        switch = {
            1: self.upload_img,
            2: self.upload_mov,
            3: self.upload_combo
        }
        ad_info, url_list = switch[play_type](upload_type, sign, urls, slot_id)
        ad_dict = dict(
            _id=generator_trade_no(),
            open_id=open_id,
            company_name=company_name,
            ad_describe=ad_describe,
            type=type,
            time_range=time_range,
            show_time=show_time,
            days=int(days),
            play_area=play_area,
            message=message,
            fee=int(fee),
            ad_status=2,  # 广告状态: 0=待支付 1=待审核 2=审核通过 3=审核失败 4=广告下架
            ad_pay_status=1,  # 0=未支付 1=已支付
            is_delete=0,  # 0=未删除 1=已删除
            create_time=datetime.datetime.now(),
            pay_time=datetime.datetime.now(),
            delete_time=None,
            scene=scene,
            source=source,
            devices=devices,
            slot_id=slot_id,
            ad_info=ad_info
        )
        try:
            db.sdec_ad_resource.insert(ad_dict)
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="广告发布失败，请稍后重试！"))
        return self.write(ret_msg(data=url_list))


class AdvertList(ApiBaseHandler):
    async def get(self):
        page_index = int(self.get_parameter("page_index", 0))
        page_size = int(self.get_parameter("page_size", 10))
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size
        data = []

        try:
            db = mongodb_util.db
            result = db.sdec_ad_resource.find().sort(
                "create_time", pymongo.DESCENDING).skip(page_start).limit(page_size)
            for ad in result:
                if ad.get("create_time", None) and ad.get("pay_time", None):
                    ad["create_time"] = ad["create_time"].strftime("%Y-%m-%d %H:%M:%S")
                    ad["pay_time"] = ad["pay_time"].strftime("%Y-%m-%d %H:%M:%S")
                data.append(ad)
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="广告查看失败！"))

        count = result.count()
        return self.write(ret_msg(data=data, error_message=count))

    async def post(self):
        id = self.get_parameter("id", None)
        key = self.get_parameter("key", None)
        if key != "o7qyl0vKx54jB05FjmxNw76SJAPE":
            return self.write(ret_msg(code=-1, error_message="没有操作权限！"))
        data = dict(_id=id)
        if not id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数！"))

        try:
            db = mongodb_util.db
            result = db.sdec_ad_resource.delete_one(data)
            if not result.deleted_count:
                return self.write(ret_msg(code=-1, error_message="广告编号不存在!"))
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="删广告失败!"))

        return self.write(ret_msg(data=result.deleted_count))


class GetAd(ApiBaseHandler):
    def sign(self, parameters):
        parameters["appkey"] = config.AD_APP_KEY
        logger.info("appkey=%s" % config.AD_APP_KEY)
        # 对各个不为空的键值对的参数名ASCII码从小到大排序（字典序）
        data = sorted(parameters.items(), key=lambda asd: asd[0], reverse=False)
        # 对参数值不为空的键值对拼接成URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串stringA
        str_a = ""
        for item in data:
            k = item[0]
            v = item[1]
            if v and k != "sign":
                str_a += k + "=" + str(v) + "&"
        str_temp = str_a[:-1]
        logger.info(str_temp)
        # 进行md5加密
        sign_value = md5(str_temp.encode())
        return sign_value

    async def three_ad(self, device_id, slot_id, ip):
        # 请求第三方广告服务器
        quantity = 8
        appid = config.AD_APP_ID
        sequence = generator_trade_no()
        timestamp = int(str(time.time() * 1000).split(".")[0])
        version = config.AD_APP_VERSION
        payload = {"device-uuid": device_id, "slot-id": slot_id, "quantity": quantity, "type": "IMG", "ip": ip}
        parameters = dict(
            payload=json.dumps(payload),
            appid=appid,
            version=version,
            sequence=sequence,
            timestamp=timestamp
        )
        sign_value = self.sign(parameters)
        parameters["sign"] = sign_value

        url = config.AD_APP_URL
        http = httpclient.AsyncHTTPClient()
        request = HTTPRequest(
            url=url,
            method="POST",
            validate_cert=False,
            request_timeout=30,
            body=urllib.parse.urlencode(parameters)
        )

        try:
            response = await http.fetch(request)
        except Exception as e:
            logger.error(e)
            return False

        if not response:
            return False

        result = json.loads(response.body.decode())
        resp = json.dumps(result)
        create_date = datetime.datetime.now()
        data = dict(
            _id=sequence,
            resp=resp,
            device_id=device_id,
            ip=ip,
            create_date=create_date
        )

        if int(result.get("code", 1)) == 0:
            db = mongodb_util.db
            db.ad_device_info.insert(data)
            logger.info("ad_device_info:success device_id=%s, ip=%s" % (device_id, ip))
        else:
            return False

        return result

    async def get(self):
        """
        TYPE: IFRAME, IMG, MOV, COMBO

        :return:
        """
        data = []
        now = datetime.datetime.now()
        year = now.year
        month = now.month
        day = now.day
        start_time = datetime.datetime(year, month, day, 11, 30, 0)
        end_time = datetime.datetime(year, month, day, 22, 30, 0)
        # 门店视频广告时间段
        start_time1 = datetime.datetime(year, month, day, 11, 30, 0)
        end_time1 = datetime.datetime(year, month, day, 13, 30, 0)
        start_time2 = datetime.datetime(year, month, day, 18, 30, 0)
        end_time2 = datetime.datetime(year, month, day, 22, 30, 0)

        class Device(object):
            pass

        class DeviceInfo(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_device_owner", "model": Device},
            {"db_table": "ebt_device", "model": DeviceInfo}
        ])

        device_id = self.get_argument("device_id", "")
        # url = "https://ad.style999.com/api/ad/track"
        device = session.query(Device).filter_by(ebf_device_id=device_id).first()
        di = session.query(DeviceInfo).filter_by(ebf_device_id=device_id).first()
        context = dict(
            code=-1,
            payload=[],
            message=None
        )
        if not (device_id and device and di):
            if device_id:
                logger.error(f"设备编号错误: device_id={device_id}")
            context["message"] = "请求参数设备编号错误"
            session.close()
            return self.write(context)

        scene = int(di.ebf_device_scene)
        if now < start_time or now > end_time:
            context["message"] = "非广告播放时间"  # 非家庭播放场景播放时间段 08:00-23:59
            session.close()
            return self.write(context)

        if device.ebf_device_wifi_code == "CWD-30E1":
            slot_id = "00000001"  # 小屏
            # slotid = config.AD_SLOT_ID1 # 请求第三方广告所需参数
        else:
            slot_id = "00000002"  # 大屏
            # slotid = config.AD_SLOT_ID2 # 请求第三方广告所需参数

        try:
            db = mongodb_util.db
            # 检查设备是否禁放广告
            filter_device = db.sdec_filter_ad_devices.find_one({"_id": device_id})
            if filter_device:
                context["message"] = "该设备禁放广告！"
                session.close()
                return self.write(context)

            # 播放第三方广告
            # ip = self.request.remote_ip
            # result = await self.three_ad(device_id, slotid, ip)
            # if result:
            #     data = result["payload"]
            #     for ad in data:
            #         content = dict()
            #         content["type"] = ad.get("type", "IMG")
            #         content["url"] = ad.pop("url", None)
            #         content["width"] = ad.pop("width", 768)
            #         content["height"] = ad.pop("height", 1341)
            #         content["sign"] = ad.pop("sign", None)
            #         content["file-size"] = ad.pop("file-size", 650)
            #         content["music-url"] = ad.pop("music-url", None)
            #         ad["content"] = [content]
            #     result = []
            # else:
            #     result = []
            #     data = []

            # 周总餐厅测试广告
            shop_devices = [100000506, 100000114, 100000574, 100000472, 100000445, 100000867, 100000579]
            shop_ad_payload = [
                {
                    "content": [{
                        "type": "MOV",
                        "url": "https://cos.style999.com/static/ad/video/1591953507197378.mp4",
                        "width": 768,
                        "height": 768,
                        "file-size": 3554581,
                        "sign": None
                    }, {
                        "type": "IMG",
                        "url": "https://cos.style999.com/static/ad/img/3151592202516_.pic_hd.jpg",
                        "width": 768,
                        "height": 573,
                        "file-size": 560837,
                        "sign": None
                    }],
                    "expire-time": None,
                    "show-time": 51,
                    "slot-id": "00000002",
                    "track-url": None,
                    "type": "COMBO"
                },
                {
                    "content": [{
                        "type": "MOV",
                        "url": "https://cos.style999.com/static/ad/video/1591953506267569.mp4",
                        "width": 768,
                        "height": 768,
                        "file-size": 5090458,
                        "sign": None
                    }, {
                        "type": "IMG",
                        "url": "https://cos.style999.com/static/ad/img/3151592202516_.pic_hd.jpg",
                        "width": 768,
                        "height": 573,
                        "file-size": 560837,
                        "sign": None
                    }],
                    "expire-time": None,
                    "show-time": 63,
                    "slot-id": "00000002",
                    "track-url": None,
                    "type": "COMBO"
                },
                {
                    "content": [{
                        "type": "MOV",
                        "url": "https://cos.style999.com/static/ad/video/1591953506313379.mp4",
                        "width": 768,
                        "height": 768,
                        "file-size": 3126997,
                        "sign": None
                    }, {
                        "type": "IMG",
                        "url": "https://cos.style999.com/static/ad/img/3151592202516_.pic_hd.jpg",
                        "width": 768,
                        "height": 573,
                        "file-size": 560837,
                        "sign": None
                    }],
                    "expire-time": None,
                    "show-time": 60,
                    "slot-id": "00000002",
                    "track-url": None,
                    "type": "COMBO"
                },
                {
                    "content": [{
                        "type": "MOV",
                        "url": "https://cos.style999.com/static/ad/video/1591953506466775.mp4",
                        "width": 768,
                        "height": 768,
                        "file-size": 3526491,
                        "sign": None
                    }, {
                        "type": "IMG",
                        "url": "https://cos.style999.com/static/ad/img/3151592202516_.pic_hd.jpg",
                        "width": 768,
                        "height": 573,
                        "file-size": 560837,
                        "sign": None
                    }],
                    "expire-time": None,
                    "show-time": 54,
                    "slot-id": "00000002",
                    "track-url": None,
                    "type": "COMBO"
                },
                {
                    "content": [{
                        "type": "MOV",
                        "url": "https://cos.style999.com/static/ad/video/1591953506473139.mp4",
                        "width": 768,
                        "height": 768,
                        "file-size": 3119852,
                        "sign": None
                    }, {
                        "type": "IMG",
                        "url": "https://cos.style999.com/static/ad/img/3151592202516_.pic_hd.jpg",
                        "width": 768,
                        "height": 573,
                        "file-size": 560837,
                        "sign": None
                    }],
                    "expire-time": None,
                    "show-time": 45,
                    "slot-id": "00000002",
                    "track-url": None,
                    "type": "COMBO"
                },
                {
                    "content": [{
                        "type": "MOV",
                        "url": "https://cos.style999.com/static/ad/video/1591953506494746.mp4",
                        "width": 768,
                        "height": 768,
                        "file-size": 2939881,
                        "sign": None
                    }, {
                        "type": "IMG",
                        "url": "https://cos.style999.com/static/ad/img/3151592202516_.pic_hd.jpg",
                        "width": 768,
                        "height": 573,
                        "file-size": 560837,
                        "sign": None
                    }],
                    "expire-time": None,
                    "show-time": 48,
                    "slot-id": "00000002",
                    "track-url": None,
                    "type": "COMBO"
                },
                {
                    "content": [{
                        "type": "MOV",
                        "url": "https://cos.style999.com/static/ad/video/1591953506514689.mp4",
                        "width": 768,
                        "height": 768,
                        "file-size": 3582706,
                        "sign": None
                    }, {
                        "type": "IMG",
                        "url": "https://cos.style999.com/static/ad/img/3151592202516_.pic_hd.jpg",
                        "width": 768,
                        "height": 573,
                        "file-size": 560837,
                        "sign": None
                    }],
                    "expire-time": None,
                    "show-time": 49,
                    "slot-id": "00000002",
                    "track-url": None,
                    "type": "COMBO"
                },
                {
                    "content": [{
                        "type": "MOV",
                        "url": "https://cos.style999.com/static/ad/video/1591953506526913.mp4",
                        "width": 768,
                        "height": 768,
                        "file-size": 2985626,
                        "sign": None
                    }, {
                        "type": "IMG",
                        "url": "https://cos.style999.com/static/ad/img/3151592202516_.pic_hd.jpg",
                        "width": 768,
                        "height": 573,
                        "file-size": 560837,
                        "sign": None
                    }],
                    "expire-time": None,
                    "show-time": 49,
                    "slot-id": "00000002",
                    "track-url": None,
                    "type": "COMBO"
                },
                {
                    "content": [{
                        "type": "MOV",
                        "url": "https://cos.style999.com/static/ad/video/1592296765072706.mp4",
                        "width": 768,
                        "height": 768,
                        "file-size": 1424237,
                        "sign": None
                    }, {
                        "type": "IMG",
                        "url": "https://cos.style999.com/static/ad/img/3151592202516_.pic_hd.jpg",
                        "width": 768,
                        "height": 573,
                        "file-size": 560837,
                        "sign": None
                    }],
                    "expire-time": None,
                    "show-time": 32,
                    "slot-id": "00000002",
                    "track-url": None,
                    "type": "COMBO"
                }
            ]

            if int(device_id) in shop_devices:
                if start_time1 < now < end_time1 or start_time2 < now < end_time2:
                    context = dict(
                        code=0,
                        message="",
                        payload=shop_ad_payload
                    )
                    session.close()
                    return self.write(context)
                else:
                    context["message"] = "非广告时段！"
                    session.close()
                    return self.write(context)

            if scene == 1:
                # 家庭数码相框
                page_size_home = 10
                page_size = 1
                random_play = 0
                item = db.sdec_device_play_ad_tab.find_one({"_id": device_id})
                flag = False  # 非第一次请求标志
                if item:
                    page_index_home = item["page_index_home"] + 1
                    page_index = item["page_index"] + 1
                    random_play = item.get("random_play", 0)
                    flag = True
                else:
                    page_index_home = 0
                    page_index = 0
                    insert_data = dict(
                        _id=device_id,
                        page_index_home=page_index_home,
                        page_size_home=page_size_home,
                        page_index=page_index,
                        page_size=page_size,
                        random_play=random_play,
                        create_time=now,
                        update_time=now
                    )
                    db.sdec_device_play_ad_tab.insert_one(insert_data)
                if random_play:
                    result_home = db.sdec_ad_resource.aggregate([
                        {'$match':
                            {
                                "slot_id": slot_id,
                                "devices": device_id,
                                "is_delete": 0,
                                "source": 1
                            }
                         },
                        {'$sample': {'size': page_size_home}}
                    ])
                    result = db.sdec_ad_resource.aggregate([
                        {'$match':
                            {
                                "slot_id": slot_id,
                                "is_delete": 0,
                                "$or": [{"source": 2, "devices": []}, {"source": 2, "devices": device_id}]
                            }
                         },
                        {'$sample': {'size': page_size}}
                    ])
                else:
                    page_start_home = page_index_home * page_size_home
                    page_start = page_index * page_size
                    result_home = db.sdec_ad_resource.find({
                        "slot_id": slot_id,
                        "devices": device_id,
                        "is_delete": 0,
                        "source": 1
                    }).sort("create_time", pymongo.DESCENDING).skip(page_start_home).limit(page_size_home)
                    result = db.sdec_ad_resource.find({
                        "slot_id": slot_id,
                        "is_delete": 0,
                        "$or": [{"source": 2, "devices": []}, {"source": 2, "devices": device_id}]
                    }).sort("create_time", pymongo.DESCENDING).skip(page_start).limit(page_size)
                    if not result_home.count(True) and page_index_home:
                        page_index_home = 0
                        page_start_home = 0
                        result_home = db.sdec_ad_resource.find({
                            "slot_id": slot_id,
                            "devices": device_id,
                            "is_delete": 0,
                            "source": 1
                        }).sort("create_time", pymongo.DESCENDING).skip(page_start_home).limit(page_size_home)
                    if not result.count(True) and page_index:
                        page_index = 0
                        page_start = 0
                        result = db.sdec_ad_resource.find({
                            "slot_id": slot_id,
                            "is_delete": 0,
                            "$or": [{"source": 2, "devices": []}, {"source": 2, "devices": device_id}]
                        }).sort("create_time", pymongo.DESCENDING).skip(page_start).limit(page_size)
                    if flag:
                        db.sdec_device_play_ad_tab.update_one(
                            {"_id": device_id},
                            {"$set": {"page_index": page_index, "page_index_home": page_index_home, "update_time": now}}
                        )
                for ad in result_home:
                    content = ad.get("ad_info", None)
                    data.append(content)
                for ad in result:
                    content = ad.get("ad_info", None)
                    data.append(content)
            else:
                # 非家庭数码相框
                page_size_home = 10
                page_size = 10
                item = db.sdec_device_play_ad_tab.find_one({"_id": device_id})
                if scene == 0:
                    find_data = [
                        {"source": 2, "devices": []},
                        {"source": 2, "devices": device_id},
                        {"devices": device_id, "source": 4},
                        {"devices": [], "source": 4},
                        {"devices": device_id, "source": 1}
                    ]
                else:
                    find_data = [
                        {"source": 2, "devices": []},
                        {"source": 2, "devices": device_id},
                        {"devices": device_id, "source": 4},
                        {"devices": [], "source": 4}
                    ]
                flag = False  # 非第一次请求标志
                if item:
                    page_index = item["page_index"] + 1
                    flag = True
                else:
                    page_index = 0
                    page_index_home = 0
                    insert_data = dict(
                        _id=device_id,
                        page_index_home=page_index_home,
                        page_size_home=page_size_home,
                        page_index=page_index,
                        page_size=page_size,
                        create_time=now,
                        update_time=now
                    )
                    db.sdec_device_play_ad_tab.insert_one(insert_data)
                page_start = page_index * page_size
                result = db.sdec_ad_resource.find({
                    "slot_id": slot_id,
                    "is_delete": 0,
                    "$or": find_data
                }).sort("create_time", pymongo.DESCENDING).skip(page_start).limit(page_size)
                if not result.count(True) and page_index:
                    page_index = 0
                    page_start = 0
                    result = db.sdec_ad_resource.find({
                        "slot_id": slot_id,
                        "is_delete": 0,
                        "$or": find_data
                    }).sort("create_time", pymongo.DESCENDING).skip(page_start).limit(page_size)
                for ad in result:
                    content = ad.get("ad_info", None)
                    data.append(content)
                if flag:
                    db.sdec_device_play_ad_tab.update_one(
                        {"_id": device_id},
                        {"$set": {"page_index": page_index, "update_time": now}}
                    )
        except Exception as e:
            logger.error(e)
            context["message"] = f"广告获取失败！{e}"
            session.close()
            return self.write(context)

        context = dict(
            code=0,
            message="",
            payload=data
        )
        session.close()
        return self.write(context)


class FilterAd(ApiBaseHandler):
    async def post(self):
        device_id = self.get_parameter("id", None)

        if not device_id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数！"))

        try:
            db = mongodb_util.db
            result = db.sdec_filter_ad_devices.find_one({"_id": device_id})
            if not result:
                db.sdec_filter_ad_devices.insert({"_id": device_id})
            else:
                return self.write(ret_msg(code=-1, error_message="该设备已经禁播广告，无需重复禁止！"))
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试！"))

        return self.write(ret_msg())


class FreeDevice(ApiBaseHandler):
    async def post(self):
        device_id = self.get_parameter("id", None)

        if not device_id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数！"))

        try:
            db = mongodb_util.db
            data = {"_id": device_id}
            result = db.sdec_filter_ad_devices.find_one(data)
            if result:
                db.sdec_filter_ad_devices.delete_one(data)
            else:
                return self.write(ret_msg(code=-1, error_message="该设备没有禁播广告，无需释放！"))
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试！"))

        return self.write(ret_msg())


class IsOwnerDevice(ApiBaseHandler):
    async def get(self):
        device_id = self.get_parameter("id", None)
        if not device_id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数！"))
        open_id = await self.get_open_id()
        result = is_owner_device(device_id, open_id)
        return self.write(ret_msg(data=result))


class PhotoAlbum(ApiBaseHandler):
    async def get(self):
        device_id = self.get_argument("did", None)
        page_index = int(self.get_argument("page_index", 0))
        page_size = int(self.get_argument("page_size", 10))
        page_start = page_index * page_size
        if not device_id:
            return self.write(ret_msg(code=-1, error_message="缺少参数设备编号"))
        open_id = await self.get_open_id()
        result = is_owner_device(device_id, open_id)
        if not result:
            return self.write(ret_msg(code=-1, error_message="只有设备主人才能查看相册！"))

        class Device(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_device_owner", "model": Device},
        ])
        device = session.query(Device).filter_by(ebf_device_id=device_id).first()
        if not device:
            session.close()
            return self.write(ret_msg(code=-1, error_message="设备编号错误！"))
        if device.ebf_device_wifi_code == "CWD-30E1":
            slot_id = "00000001"
        else:
            slot_id = "00000002"
        data = []
        try:
            db = mongodb_util.db
            item = db.sdec_device_play_ad_tab.find_one({"_id": device_id})
            random_play = 0
            if item:
                random_play = item.get("random_play", 0)
            photos = db.sdec_ad_resource.find({
                "slot_id": slot_id,
                "devices": device_id,
                "is_delete": 0,
                "source": 1
            }).sort("create_time", pymongo.DESCENDING).skip(page_start).limit(page_size)
            for p in photos:
                id = p["_id"]
                ad_info = p["ad_info"]
                # 列表的目的在于兼容图片视频组合相册
                urls = []
                content = ad_info["content"]
                for c in content:
                    urls.append(c["url"])
                photo = dict(
                    id=id,
                    urls=urls
                )
                data.append(photo)
            session.close()
            return self.write(ret_msg(data=data, error_message=str(random_play)))
        except Exception as e:
            logger.error(e)
            session.close()
            return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试！"))

    async def post(self):
        id = self.get_parameter("id", None)
        device_id = self.get_parameter("did", None)
        del_type = int(self.get_parameter("del_type", 0))  # 0=删除指定单个id的照片 1=删除指定id列表的照片 2=删除所有照片
        logger.info("type(id)=%s, id=%s, device_id=%s" % (type(id), id, device_id))
        if not device_id:
            return self.write(ret_msg(code=-1, error_message="缺少参数设备编号"))
        open_id = await self.get_open_id()
        result = is_owner_device(device_id, open_id)
        if not result:
            return self.write(ret_msg(code=-1, error_message="只有设备主人才能删除照片！"))

        class Device(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_device_owner", "model": Device},
        ])
        device = session.query(Device).filter_by(ebf_device_id=device_id).first()
        if not device:
            session.close()
            return self.write(ret_msg(code=-1, error_message="设备编号错误"))

        if device.ebf_device_wifi_code == "CWD-30E1":
            slot_id = "00000001"  # 小屏
        else:
            slot_id = "00000002"  # 大屏

        if del_type != 2 and not isinstance(id, list):
            return self.write(ret_msg(code=-1, error_message="传入的参数应为数组"))
        if not id and del_type != 2:
            return self.write(ret_msg(code=-1, error_message="缺少参数照片编号"))

        if del_type == 0:
            data = dict(_id=id[0])
        elif del_type == 1 and len(id) > 1:
            data = {"_id": {"$in": id}}
        elif del_type == 2:
            data = {
                "slot_id": slot_id,
                "devices": device_id,
                "is_delete": 0,
                "source": 1
            }
        else:
            return self.write(ret_msg(code=-1, error_message="请求参数错误"))

        try:
            db = mongodb_util.db
            result = db.sdec_ad_resource.delete_many(data)
            if not result.deleted_count:
                return self.write(ret_msg(code=-1, error_message="照片不存在!"))
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="删除照片失败，请稍后重试!"))
        return self.write(ret_msg(data=result.deleted_count))


class RandomPlay(ApiBaseHandler):
    async def post(self):
        device_id = self.get_parameter("did", None)
        random_play = int(self.get_parameter("random_play", 0))
        if not device_id:
            return self.write(ret_msg(code=-1, error_message="缺少参数设备编号"))

        open_id = await self.get_open_id()
        result = is_owner_device(device_id, open_id)
        if not result:
            return self.write(ret_msg(code=-1, error_message="只有设备主人才能设置是否随机播放！"))

        try:
            db = mongodb_util.db
            now = datetime.datetime.now()
            item = db.sdec_device_play_ad_tab.find_one({"_id": device_id})
            if item:
                db.sdec_device_play_ad_tab.update_one(
                    {"_id": device_id},
                    {"$set": {"random_play": random_play, "update_time": now}}
                )
            else:
                page_size_home = 10
                page_size = 1
                page_index_home = 0
                page_index = 0
                insert_data = dict(
                    _id=device_id,
                    page_index_home=page_index_home,
                    page_size_home=page_size_home,
                    page_index=page_index,
                    page_size=page_size,
                    random_play=random_play,
                    create_time=now,
                    update_time=now
                )
                db.sdec_device_play_ad_tab.insert_one(insert_data)
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试"))
        return self.write(ret_msg())
